using Client.Framework;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

[DisallowMultipleComponent]
[RequireComponent(typeof(GridLayoutGroup))]
public class VirtualList : MonoBehaviour
{
    private ScrollRect scrollRect;
    private GridLayoutGroup layout;
    private RectTransform content;

    public Transform child_prefab;
    UnityAction<Transform, int> action;

    float cell_size;
    float prefab_sizeX;
    float prefab_sizeY;

    private int max_rows;
    private int dataCount;

    private void Awake()
    {
        content = GetComponent<RectTransform>();
        layout = GetComponent<GridLayoutGroup>();
        scrollRect = GetComponentInParent<ScrollRect>();
        if (!CheckVirtualInfo()) { return; }

        cell_size = layout.cellSize.y + layout.spacing.y;
        int padding = layout.padding.top + layout.padding.bottom;
        float screen_size = scrollRect.viewport.rect.height - padding;
        if (scrollRect.horizontal)
        {
            cell_size = layout.cellSize.x + layout.spacing.x;
            padding = layout.padding.left + layout.padding.right;
            screen_size = scrollRect.viewport.rect.width - padding;
        }

        max_rows = Mathf.CeilToInt(screen_size / cell_size);
        max_rows = (max_rows + 2) * layout.constraintCount;
        scrollRect.onValueChanged.AddListener((call) => OnScrollRectChange());

        if (child_prefab == null)
        {
            child_prefab = transform.GetChild(0);
        }
        layout.enabled = false; CreatItemPrefab();
    }

    public void CreatItemPrefab(System.Action<GameObject, int> func = null)
    {
        if (child_prefab == null) { return; }
        var rectTrans = child_prefab.GetComponent<RectTransform>();
        child_prefab.gameObject.SetActive(false);
        rectTrans.pivot = new Vector2(0, 1f);

        prefab_sizeX = layout.cellSize.x * child_prefab.localScale.x;
        prefab_sizeY = layout.cellSize.y * child_prefab.localScale.y;
        Utility.AddChildren(transform, child_prefab.gameObject, max_rows, func);
    }

    public void OnRefreshChange(int dataCount, UnityAction<Transform, int> unityAction, bool change = true)
    {
        this.dataCount = dataCount; action = unityAction;
        var row = Mathf.CeilToInt(dataCount * 1.0f / layout.constraintCount);
        if (scrollRect.horizontal)
        {
            content.sizeDelta = new Vector2(row * cell_size, content.sizeDelta.y);
        }
        else
        {
            content.sizeDelta = new Vector2(content.sizeDelta.x, row * cell_size);
        }

        if (change)
        {
            scrollRect.normalizedPosition = new Vector2(0, 1);
        }
        OnScrollRectChange();
    }

    private void OnScrollRectChange()
    {
        if (!CheckVirtualInfo()) { return; }
        Vector3 anchoredPosition = scrollRect.content.anchoredPosition;
        var start_idx = Mathf.FloorToInt(anchoredPosition.y / cell_size);
        if (scrollRect.horizontal)
        {
            start_idx = Mathf.FloorToInt(anchoredPosition.x / -cell_size);
        }
        
        start_idx = Mathf.Max(start_idx - 1, 0) * layout.constraintCount;
        for (int i = 0; i < transform.childCount; i++)
        {
            int index = start_idx + i;
            var child = (RectTransform)transform.GetChild(i);
            child.gameObject.SetActive(index < dataCount);

            int row = index / layout.constraintCount;
            var col = index % layout.constraintCount;
            var x = layout.padding.left + col * prefab_sizeX + layout.spacing.x * col;
            var y = layout.padding.top + row * prefab_sizeY + layout.spacing.y * row;

            if (scrollRect.horizontal)
            {
                x = layout.padding.left + row * prefab_sizeX + layout.spacing.x * row;
                y = layout.padding.top + col * prefab_sizeY + layout.spacing.y * col;
            }

            child.localPosition = new Vector3(x, -y, 0);
            if (index < dataCount)
            {
                action?.Invoke(child, index);
            }
        }
    }

    private bool CheckVirtualInfo()
    {
        return scrollRect != null && layout != null;
    }
}